package org.lemon.cla.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.lemon.cla.enums.HttpStatusEnum;
import org.lemon.cla.dto.response.ResponseResult;
import org.lemon.cla.dto.request.NewsCreateRequest;
import org.lemon.cla.dto.request.NewsSearchRequest;
import org.lemon.cla.pojo.News;
import org.lemon.cla.vo.NewsVo;
import org.lemon.cla.enums.NewsCategoryEnum;
import org.lemon.cla.service.INewsService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

import org.lemon.cla.exception.BusinessException; // 导入自定义业务异常


@RestController
@RequestMapping("/news")
@Tag(name = "新闻管理", description = "提供新闻信息的 CRUD 和查询接口")
public class NewsController {

    @Autowired
    private INewsService newsService;

    @Operation(summary = "获取所有新闻", description = "分页获取所有新闻列表，**包含发布者信息 (若发布者被逻辑删除则显示为未知)**")
    @GetMapping
    public ResponseResult<IPage<NewsVo>> getAllNews(
            @Parameter(description = "页码", example = "1") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页数量", example = "10") @RequestParam(defaultValue = "10") Integer pageSize) {
        Page<NewsVo> page = new Page<>(pageNum, pageSize);
        IPage<NewsVo> newsPage = newsService.getAllNewsVo(page); // 调用 Service 层的新方法
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), newsPage);
    }

    @Operation(summary = "根据ID获取新闻", description = "根据新闻ID获取新闻详情，**包含发布者信息 (若发布者被逻辑删除则显示为未知)**")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取新闻"),
            @ApiResponse(responseCode = "404", description = "新闻未找到")
    })
    @GetMapping("/getNewsById/{id}")
    public ResponseResult<NewsVo> getNewsById(
            @Parameter(description = "新闻ID", required = true, example = "1") @PathVariable Long id) {
        // 使用Optional简化null检查，如果未找到则抛出 NotFoundException
        return Optional.ofNullable(newsService.getNewsVoById(id))
                .map(newsVo -> ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), newsVo))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "新闻未找到。")); // 抛出 NotFoundException
    }

    @Operation(summary = "根据ID增加新闻浏览量", description = "根据ID将新闻浏览量+1")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "浏览量增加成功"),
            @ApiResponse(responseCode = "404", description = "新闻未找到"),
            @ApiResponse(responseCode = "500", description = "更新浏览量失败")
    })
    @PostMapping("/addViewCount/{id}")
    @PreAuthorize("isAuthenticated()")
    public ResponseResult<Void> addViewCountByNewsId(
            @Parameter(description = "新闻ID", required = true, example = "1") @PathVariable Long id) {
        News news = Optional.ofNullable(newsService.getById(id))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "新闻未找到。")); // 如果新闻不存在，抛出 NotFoundException

        Integer currentViewCount = Optional.ofNullable(news.getViewCount()).orElse(0); // Optional处理null
        news.setViewCount(currentViewCount + 1);

        boolean success = newsService.updateById(news);
        if (!success) { // 如果更新返回false
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "更新浏览量失败，请稍后重试。"); // 抛出 ServiceException
        }
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), "新闻浏览量增加成功", null);
    }

    @Operation(summary = "创建新新闻", description = "创建一个新的新闻记录")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "新闻创建成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PostMapping
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<News> createNews(
            @Parameter(description = "新闻对象 (无需传入 newsId, viewCount, publishTime)", required = true) @RequestBody @Valid NewsCreateRequest request) {
        News news = new News();
        BeanUtils.copyProperties(request, news);
        news.setPublishTime(LocalDateTime.now());
        news.setViewCount(0); // 新创建的新闻浏览量默认为0

        boolean success = newsService.save(news);
        if (!success) { // 如果保存操作返回false但没有异常抛出
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "新闻创建失败，请稍后重试。");
        }
        // 返回前可以根据需要获取完整的NewsVo
        return ResponseResult.success(HttpStatusEnum.CREATED.getCode(), HttpStatusEnum.CREATED.getMessage(), news);
    }

    @Operation(summary = "更新新闻", description = "根据新闻ID更新新闻信息")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "新闻更新成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误"),
            @ApiResponse(responseCode = "404", description = "新闻未找到"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PutMapping("/editById/{id}")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<News> updateNews(
            @Parameter(description = "新闻ID", required = true, example = "1") @PathVariable Long id,
            @Parameter(description = "更新后的新闻对象", required = true) @RequestBody News news) {
        // 校验ID匹配
        Optional.ofNullable(news.getNewsId())
                .filter(newsId -> newsId.equals(id))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "请求路径中的ID与请求体中的ID不匹配。")); // 抛出 BadRequestException

        // 校验新闻是否存在
        Optional.ofNullable(newsService.getById(id))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "新闻未找到。")); // 抛出 NotFoundException

        boolean success = newsService.updateById(news);
        if (!success) { // 如果更新返回false
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "新闻更新失败，请稍后重试。"); // 抛出 ServiceException
        }
        // 返回前可以根据需要获取完整的NewsVo
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), news);
    }

    @Operation(summary = "删除新闻", description = "根据新闻ID删除新闻")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "新闻删除成功"),
            @ApiResponse(responseCode = "404", description = "新闻未找到"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @DeleteMapping("/deleteById/{id}")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<Void> deleteNews(
            @Parameter(description = "新闻ID", required = true, example = "1") @PathVariable Long id) {
        boolean success = newsService.removeById(id);
        if (!success) { // 如果删除返回false
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "新闻未找到或删除失败。"); // 抛出 NotFoundException
        }
        return ResponseResult.success(HttpStatusEnum.NO_CONTENT.getCode(), HttpStatusEnum.NO_CONTENT.getMessage(), null);
    }

    @Operation(summary = "根据类别查询新闻", description = "根据新闻类别查询新闻列表，**包含发布者信息 (若发布者被逻辑删除则显示为未知)**")
    @GetMapping("/searchByCategory/{categoryStr}") // 此接口仍保留，但内部调用统一搜索
    public ResponseResult<List<NewsVo>> getNewsByCategory(
            @Parameter(description = "新闻类别", required = true, example = "学术", schema = @Schema(implementation = NewsCategoryEnum.class))
            @PathVariable String categoryStr) {
        // 转换枚举，如果无效则 fromDescription 抛出 IllegalArgumentException，由GlobalExceptionHandler处理
        NewsCategoryEnum category = NewsCategoryEnum.fromDescription(categoryStr);

        NewsSearchRequest searchRequest = new NewsSearchRequest();
        searchRequest.setCategory(category);
        Page<NewsVo> page = new Page<>(1, -1); // -1表示不分页，获取所有匹配项
        IPage<NewsVo> resultPage = newsService.searchNewsByConditions(page, searchRequest);
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), resultPage.getRecords());
    }

    @Operation(summary = "模糊查询新闻(查询首选)", description = "根据标题、发布人姓名、发布时间范围和类别进行模糊查询，**返回包含发布人姓名的视图对象 (若发布者被逻辑删除则显示为未知)**")
    @PostMapping("/search")
    public ResponseResult<IPage<NewsVo>> searchNews(
            @Parameter(description = "页码", example = "1") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页数量", example = "10") @RequestParam(defaultValue = "10") Integer pageSize,
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "新闻查询请求对象 (可选，用于筛选)",
                    required = false,
                    content = @Content(schema = @Schema(implementation = NewsSearchRequest.class))
            ) @org.springframework.web.bind.annotation.RequestBody NewsSearchRequest request) {

        Page<NewsVo> page = new Page<>(pageNum, pageSize);

        // 使用Optional简化，确保request总是一个非null的实例
        request = Optional.ofNullable(request).orElseGet(NewsSearchRequest::new);

        IPage<NewsVo> resultPage = newsService.searchNewsByConditions(page, request);

        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), resultPage);
    }
}
